/* Filename: add.c
 * No.88.线程-竞争故障
 * Description: 20个线程同时读写文件
 * $ gcc -Wall add.c -o add -lpthread
 * $ echo 1 > /tmp/out
 * $ ./add && cat /tmp/out
 * Last modified: humble 2020-09-02 09:03:58
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>

#define THRNUM (20)
#define LINEBUFSIZE (1024)
#define FNAME "/tmp/out"

//demo0 不带互斥量，同时读写资源发生冲突
//demo1 使用互斥量，争抢资源，非同时读写
#define demo (1) //0,1

#if (demo == 1)
static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
#endif

static void *thr_add(void *p)
{
    FILE *fp;
    char linebuf[LINEBUFSIZE];

    fp = fopen(FNAME, "r+");
    if(!fp){
        perror("fopen()");
        exit(1);
    }

#if (demo == 1)
    pthread_mutex_lock(&mut);
#endif

    fgets(linebuf, LINEBUFSIZE, fp);
    fseek(fp, 0, SEEK_SET);
#if (demo == 0)
    sleep(1); //扩大竞争时间域，等全部线程都读取完毕，再往下操作
#endif
    fprintf(fp, "%d\n", atoi(linebuf) + 1);
    fclose(fp); //刷新缓冲区，不能放到unlock后面

#if (demo == 1)
    pthread_mutex_unlock(&mut);
#endif

    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    int i, err;
    pthread_t tid[THRNUM];

    for(i = 0; i < THRNUM; i++){
        err = pthread_create(tid + i, NULL, thr_add, NULL);
        if(err){
            //while(--i < 0){ pthread_join(tid[i - LEFT], NULL); } //未测
            fprintf(stderr, "pthread_create():%s\n", strerror(err));
            exit(1);
        }
    }

    for(i = 0; i < THRNUM; i++){
        pthread_join(tid[i], NULL);
    }

#if (demo == 1)
    pthread_mutex_destroy(&mut); //对应 pthread_mutex_init()
#endif
    return 0;
}
